package com.fzy.core;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.fzy.core.entity.EntityId;
import com.fzy.core.entity.EntityRecord;
import com.fzy.core.entity.EntityStatus;

public class BaseService {

	private final Logger log = Logger.getLogger(BaseService.class);
	public static final int DEFAULT_SEQUENCE_LENGTH = 10;
	protected SessionFactory sessionFactory;
	protected JdbcTemplate jdbcTemplate;

	public Session getSession(Object entity) {
		return sessionFactory.getCurrentSession();
	}

	public Object get(Class clazz, Serializable id) {
		return sessionFactory.getCurrentSession().get(clazz, id);
	}

	public void save(Object entity) {
		sessionFactory.getCurrentSession().save(entity);
	}

	public void update(Object entity) {
		sessionFactory.getCurrentSession().update(entity);
	}
	
	/** if this object has id, and find nothing by this id, return false; 
	 * 	else return true
	 * @param entityObj
	 * @return
	 */
	public boolean syncEntityById(EntityId entityObj){
		Long id = entityObj.getId();
		if(id == null){
			// not need to synchronize
			return true;
		}
		Class clazz = entityObj.getClass();
		Object entity = sessionFactory.getCurrentSession().get(clazz, id);
		if(entity == null){
			return false;
		}else{
			entityObj = (EntityId) entity;
			return true;
		}
	}

	public void saveEntityId(EntityId entity) {
		Long id = entity.getId();
		// is creating entity
		boolean isCreated = id == null;

		// record fields
		if (entity instanceof EntityRecord) {
			EntityRecord entityRecord = (EntityRecord) entity;
			if (isCreated) {
				entityRecord.setCreatedDate(new Date());
				entityRecord.setCreatedUser(new Long(0));
			} else {
				entityRecord.setUpdatedDate(new Date());
				entityRecord.setUpdatedUser(new Long(0));
			}
		}

		// status field
		if (entity instanceof EntityStatus) {
			EntityStatus entityStatus = (EntityStatus) entity;
			entityStatus.setStatus("1");
		}

		if (isCreated)
			save(entity);
		else
			update(entity);

	}

	public List query(String sql, RowMapper rowMapper) {
		try {
			return jdbcTemplate.query(sql, rowMapper);
		} catch (Exception e) {
			handleSqlError(e, sql, null);
		}
		return new LinkedList();
	}

	public List query(String sql, Object[] params, RowMapper rowMapper) {
		try {
			return jdbcTemplate.query(sql, params, rowMapper);
		} catch (Exception e) {
			handleSqlError(e, sql, params);
		}
		return new LinkedList();
	}

	public Page queryPage(String sql, Object[] params, RowMapper mapper,
			Page page) {
		try {
			return (Page) jdbcTemplate.query(
					new MyPreparedStatementCreator(sql),
					new MyPreparedStatementSetter(params),
					new MyRowMapperResultSetExtractor(mapper, page));
		} catch (Exception e) {
			handleSqlError(e, sql, params);
		}
		return new Page();
	}

	public int update(String sql) {
		return update(sql, new Object[] {});
	}

	public int update(String sql, List params) {
		return update(sql, params == null ? null : params.toArray());
	}

	public int update(String sql, Object[] params) {
		int num = 0;
		try {
			num = jdbcTemplate.update(sql, params);
		} catch (Exception e) {
			handleSqlError(e, sql, params);
		}
		log.info("SQL:" + sql);
		log.info("PARAMETERS:");
		if (params != null)
			for (int i = 0; i < params.length; i++) {
				log.info(params[i]);
			}
		return num;
	}

	public Object queryForFirst(String sql, Object[] params, RowMapper mapper) {
		Object result = null;
		try {
			List l = jdbcTemplate.query(sql, params, mapper);
			if (l.size() > 0)
				result = l.get(0);
		} catch (Exception e) {
			handleSqlError(e, sql, params);
		}
		return result;
	}

	public String getSequenceString(String sequenceName) throws Exception {
		return getSequenceString(sequenceName, DEFAULT_SEQUENCE_LENGTH);
	}

	public String getSequenceString(String sequenceName, int length) throws Exception {
		long seq = getSequence(sequenceName);
		return U.number2string(seq, length);
	}

	protected String getSqlAndSetParams(List params, String sql, Object param) {
		String result = "";
		if (param != null && !"".equals(param.toString().trim())) {
			result += sql;
			if (param instanceof String) {
				param = ((String) param).trim();
			}
			params.add(param);
		}
		return result;
	}

	protected String getOrderSql(String fieldName, String columnName,
			PageForm form) {
		String result = "";
		if (!StringUtils.isBlank(form.getOrderBy())) {
			if (fieldName.equalsIgnoreCase(form.getOrderBy())) {
				if ("desc".equalsIgnoreCase(form.getOrder())) {
					result += " order by " + columnName + " desc";
				}
				if ("asc".equalsIgnoreCase(form.getOrder())) {
					result += " order by " + columnName + " asc";
				}
			}
		}
		return result;
	}

	protected String getConditionSqlDateBeginEnd(String beginDateString,
			String endDateString, String columnName, List params) {
		Date beginDate = U.parseDate(beginDateString);
		Date endDate = U.parseDateEnd(endDateString);
		return getConditionSqlDateBeginEnd(beginDate, endDate, columnName,
				params);
	}

	protected String getConditionSqlDateBeginEnd(Date beginDate, Date endDate,
			String columnName, List params) {
		String result = "";
		if (StringUtils.isBlank(columnName))
			return result;
		if (beginDate != null) {
			result += " and " + columnName + " >= ?";
			params.add(U.LONG_DATE_FORMAT.format(beginDate));
		}
		if (endDate != null) {
			result += " and " + columnName + " <= ?";
			params.add(U.LONG_DATE_FORMAT.format(endDate));
		}
		return result;
	}

	protected String getConditionSql(Object value, String condition, List params) {
		return getConditionSql(value, condition, params, false);
	}

	protected String getConditionSql(Object value, String condition,
			List params, boolean isLikeCondition) {
		String result = "";
		boolean valid = false;
		if (value != null) {
			if (value instanceof String) {
				if (!StringUtils.isBlank((String) value)) {
					valid = true;
				}
			} else {
				valid = true;
			}
		}
		if (valid) {
			result = " and " + condition + " ?";
			if (isLikeCondition) {
				params.add(likeParam((String) value));
			} else {
				params.add(value);
			}
		}
		return result;
	}

	protected String likeParam(String param) {
		return "%" + StringUtils.trim(param) + "%";
	}

	protected String likeRightParam(String param) {
		return StringUtils.trim(param) + "%";
	}

	protected String likeLeftParam(String param) {
		return "%" + StringUtils.trim(param);
	}

	private void handleSqlError(Exception e, String sql, Object[] params) {
		log.error("ERROR SQL:" + sql);
		log.error("ERROR PARAMETERS:");
		if (params != null)
			for (int i = 0; i < params.length; i++) {
				log.error(params[i]);
			}
		log.error("", e);
	}

	public long getSequence(String sequenceName) throws Exception {
		String sql = "select " + SqlUtils.nextval(sequenceName) + " from dual";
		SQLQuery s = sessionFactory.getCurrentSession().createSQLQuery(sql);
		long number = 0;
		try {
			BigInteger x = (BigInteger) s.uniqueResult();
			number = x.longValue();
		} catch (Exception e) {
			log.error("ERROR SQL:" + sql);
			log.error(e);
			throw e;
		}
		return number;
	}
	
	protected Session getSession(){
		return sessionFactory.getCurrentSession();
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

}
